# /**
# * Copyright (c) 2022 Beijing Jiaotong University
# * PhotLab is licensed under [Open Source License].
# * You can use this software according to the terms and conditions of the [Open Source License].
# *
# * You may obtain a copy of [Open Source License] at: [https://open.source.license/]
# *
# * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# *
# * See the [Open Source License] for more details.
# */
# /**
# * Author: Shihao Xie
# * Created: Sep. 3, 2022
# * Supported by: National Key Research and Development Program of China
# */
import os
from phot_server.server_config.global_config import CONFIG_FILE_NAME
from phot_server.core.exception import FilePathError
from phot_server.factory.graph_factory import GraphFactory
from phot_server.factory.project_factory import ProjectFactory
from phot_server.manager.graph_manager import GraphManager
from phot_server.manager.grid_manager import GridManager
from phot_server.rpc.device_data_type.ttypes import PhotGrid
from phot_server.rpc.file_data_type.ttypes import PhotFileType, PhotFile
from phot_server.rpc.project_data_type.ttypes import ProjectConfig, ProjectType
from phot_server.repository.project_config_repository import ProjectConfigRepository
from phot_server.utils.phot_file import open_directory, open_file, new_directory, is_project, get_file_list, new_file, delete, save
from phot_server.utils.phot_logger import logger
from phot_server.utils.phtg import save_phtg
from phot_server.utils.phtl import parse_phtl, save_phtl
from phot_server.utils.toml_parser import save_toml
from phot_server.utils.type_convert import object_to_dict


class ProjectManager:
    def __init__(self):
        logger.debug("Library Manager is Initailizing!")
        self.__repository = ProjectConfigRepository()
        self.__factory = ProjectFactory()
        self.__graph_manager = GraphManager()
        self.__grid_manager = GridManager()

    def open_directory(self, directory_path: str) -> list:
        return open_directory(directory_path)

    def open_file(self, file_path: str) -> PhotFile:
        return open_file(file_path)

    def new_project(self, project_path, project_name, project_type) -> ProjectConfig:
        project_config = self.__factory.get_new_project_config(project_path, project_name, project_type)
        for file in project_config.files:
            if file.type == PhotFileType.DIRECTORY:
                new_directory(directory_path=os.path.join(project_path, file.path))
            elif file.type == PhotFileType.CONFIG:
                save_phtl(os.path.join(project_path, file.path), project_config)
            elif file.type == PhotFileType.GRAPH:
                graph_factory = GraphFactory()
                save_phtg(os.path.join(project_path, file.path), graph_factory.get_new_phot_graph(project_name),
                          graph_factory.get_new_render_graph(project_name))
            elif file.type == PhotFileType.GRID:
                save_toml(os.path.join(project_path, file.path), object_to_dict(PhotGrid()))
        return project_config

    def open_project(self, project_path) -> ProjectConfig:
        if is_project(project_path) is False:
            raise FilePathError("There is not a file named 'config.phtl' in the project path.")
        project_config = parse_phtl(os.path.join(project_path, CONFIG_FILE_NAME))
        project_config.projectDirectory = project_path
        self.__repository.add_project_config(project_config)
        self.refresh_project(project_id=project_config.projectId)
        return project_config

    def close_project(self, project_id, window_config):
        project_config = self.__repository.get_project_config(project_id)
        self.__repository.delete_project_config(project_id)
        if project_config.projectType == ProjectType.Optical_fiber_communication_simulation \
                and self.__graph_manager.has_graph(project_config.mainFileName):
            self.__graph_manager.save_graph(project_config.mainFileName)
            self.__graph_manager.close_graph(project_config.mainFileName)
        elif project_config.projectType == ProjectType.Optical_device_simulation \
                and self.__grid_manager.has_grid(project_config.mainFileName):
            self.__grid_manager.save_grid(project_config.mainFileName)
            self.__grid_manager.delete_grid(project_config.mainFileName)
        project_path = project_config.projectDirectory
        project_config.files = self.open_directory(project_path)
        project_config.windowConfig = window_config
        save_phtl(os.path.join(project_path, CONFIG_FILE_NAME), project_config)

    def refresh_project(self, project_id):
        project_config = self.__repository.get_project_config(project_id)
        project_path = project_config.projectDirectory
        directory_stack = [project_path]
        phot_file_list = []
        while len(directory_stack) != 0:
            directory_path = directory_stack.pop(-1)
            for phot_file_object in self.open_directory(directory_path):
                if phot_file_object.type == PhotFileType.DIRECTORY:
                    directory_stack.append(phot_file_object.path)
                phot_file_list.append(phot_file_object)
        project_config.files = phot_file_list
        self.__repository.update_project_config(project_id, project_config)
        return project_config

    def new_directory(self, directory_path: str):
        new_directory(directory_path)

    def new_file(self, file_path: str, file_object: PhotFile):
        new_file(file_path, file_object)

    def delete(self, path):
        delete(path)

    def save_file(self, file_path: str, file_object: PhotFile):
        save(file_path, file_object)

